package vec

import (
	"buding-ai/pkg/config"
	"context"
	"fmt"
	"log"
	"time"

	"github.com/qdrant/go-client/qdrant"
	"google.golang.org/grpc"
)

var Client *QdrantClient

func init() {
	var err error

	Client, err = NewQdrantClient(config.GetConfig().QD.URI)
	if err != nil {
		log.Fatalf("qdrant client faild")
	}
	log.Println("qdrant client success")
}

// QdrantClient 表示Qdrant客户端
type QdrantClient struct {
	client       qdrant.CollectionsClient
	pointsClient qdrant.PointsClient
	conn         *grpc.ClientConn
}

// NewQdrantClient 创建一个新的Qdrant客户端
func NewQdrantClient(address string) (*QdrantClient, error) {
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		return nil, fmt.Errorf("连接Qdrant失败: %v", err)
	}

	// 测试连接
	collectionsClient := qdrant.NewCollectionsClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	_, err = collectionsClient.List(ctx, &qdrant.ListCollectionsRequest{})
	if err != nil {
		conn.Close()
		return nil, fmt.Errorf("列出集合失败(连接测试): %v", err)
	}

	return &QdrantClient{
		client:       collectionsClient,
		pointsClient: qdrant.NewPointsClient(conn),
		conn:         conn,
	}, nil
}

// Close 关闭客户端连接
func (q *QdrantClient) Close() {
	if q.conn != nil {
		q.conn.Close()
	}
}

// CreateCollection 创建集合
func (q *QdrantClient) CreateCollection(collectionName string, vectorSize uint64) error {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	var resp *qdrant.CollectionExistsResponse
	var err error
	// 检查集合是否存在
	if resp, err = q.client.CollectionExists(ctx, &qdrant.CollectionExistsRequest{CollectionName: collectionName}); err != nil {
		return err
	}
	if resp.GetResult().GetExists() {
		return nil
	}
	// 如果得到错误，可能是集合不存在，尝试创建它
	_, err = q.client.Create(ctx, &qdrant.CreateCollection{
		CollectionName: collectionName,
		VectorsConfig: &qdrant.VectorsConfig{
			Config: &qdrant.VectorsConfig_Params{
				Params: &qdrant.VectorParams{
					Size:     vectorSize,
					Distance: qdrant.Distance_Cosine,
				},
			},
		},
	})
	if err != nil {
		return fmt.Errorf("创建集合失败: %v", err)
	}
	log.Printf("成功创建集合: %s", collectionName)
	return nil
}

// AddPoint 添加单个点到Qdrant
func (q *QdrantClient) AddPoint(collectionName string, id uint64, vector []float32, payload map[string]interface{}) error {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	var err error
	if err = q.CreateCollection(collectionName, 2000); err != nil {
		return err
	}
	lenth := len(vector)
	if lenth < 2000 {
		vector = append(vector, make([]float32, 2000-lenth)...)
	}
	// 添加调试日志
	log.Printf("正在添加点，ID: %d", id)
	log.Printf("Payload 内容: %+v", payload)

	qdrantPayload, err := convertToQdrantPayload(payload)
	if err != nil {
		log.Printf("Payload 转换错误: %v", err)
		return fmt.Errorf("转换payload失败: %v", err)
	}

	log.Printf("转换后的 Qdrant Payload: %+v", qdrantPayload)

	pointStruct := &qdrant.PointStruct{
		Id: &qdrant.PointId{
			PointIdOptions: &qdrant.PointId_Num{
				Num: id,
			},
		},
		Vectors: &qdrant.Vectors{
			VectorsOptions: &qdrant.Vectors_Vector{
				Vector: &qdrant.Vector{
					Data: vector,
				},
			},
		},
		Payload: qdrantPayload,
	}

	upsertRequest := &qdrant.UpsertPoints{
		CollectionName: collectionName,
		Points:         []*qdrant.PointStruct{pointStruct},
	}

	response, err := q.pointsClient.Upsert(ctx, upsertRequest)
	if err != nil {
		log.Printf("Upsert错误: %v", err)
		return fmt.Errorf("添加点失败: %v", err)
	}

	log.Printf("Upsert响应: %+v", response)
	return nil
}

// AddPoints 批量添加多个点到Qdrant
func (q *QdrantClient) AddPoints(collectionName string, ids []uint64, vectors [][]float32, payloads []map[string]interface{}) error {
	if len(ids) != len(vectors) || len(ids) != len(payloads) {
		return fmt.Errorf("ids、vectors和payloads的长度必须相同")
	}

	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	points := make([]*qdrant.PointStruct, 0, len(ids))

	for i := 0; i < len(ids); i++ {
		qdrantPayload, err := convertToQdrantPayload(payloads[i])
		if err != nil {
			return fmt.Errorf("转换payload %d 失败: %v", i, err)
		}

		pointStruct := &qdrant.PointStruct{
			Id: &qdrant.PointId{
				PointIdOptions: &qdrant.PointId_Num{
					Num: ids[i],
				},
			},
			Vectors: &qdrant.Vectors{
				VectorsOptions: &qdrant.Vectors_Vector{
					Vector: &qdrant.Vector{
						Data: vectors[i],
					},
				},
			},
			Payload: qdrantPayload,
		}

		points = append(points, pointStruct)
	}

	upsertRequest := &qdrant.UpsertPoints{
		CollectionName: collectionName,
		Points:         points,
	}

	_, err := q.pointsClient.Upsert(ctx, upsertRequest)
	if err != nil {
		return fmt.Errorf("批量添加点失败: %v", err)
	}

	response, err := q.pointsClient.Upsert(ctx, upsertRequest)
	if err != nil {
		log.Printf("Upsert错误: %v", err)
		return fmt.Errorf("添加点失败: %v", err)
	}

	log.Printf("Upsert响应: %+v", response)
	return nil
}

// SearchPoints 搜索点
func (q *QdrantClient) SearchPoints(collectionName string, vector []float32, limit uint64, scoreThreshold float32) ([]*qdrant.ScoredPoint, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	lenth := len(vector)
	if lenth < 2000 {
		vector = append(vector, make([]float32, 2000-lenth)...)
	}

	searchRequest := &qdrant.SearchPoints{
		CollectionName: collectionName,
		Vector:         vector,
		Limit:          limit,
		ScoreThreshold: &scoreThreshold,
		WithPayload: &qdrant.WithPayloadSelector{
			SelectorOptions: &qdrant.WithPayloadSelector_Enable{
				Enable: true,
			},
		},
	}

	response, err := q.pointsClient.Search(ctx, searchRequest)
	if err != nil {
		return nil, fmt.Errorf("搜索点失败: %v", err)
	}

	// 添加调试日志
	for _, point := range response.Result {
		log.Printf("搜索结果 - ID: %v, Score: %v, Payload: %+v",
			point.Id, point.Score, point.Payload)
	}

	return response.Result, nil
}

// DeletePoint 删除单个点
func (q *QdrantClient) DeletePoint(collectionName string, id uint64) error {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	log.Printf("正在删除点，ID: %d, 集合: %s", id, collectionName)

	// 构建点ID数组
	pointId := &qdrant.PointId{
		PointIdOptions: &qdrant.PointId_Num{
			Num: id,
		},
	}

	// 创建删除请求
	deleteRequest := &qdrant.DeletePoints{
		CollectionName: collectionName,
		Points: &qdrant.PointsSelector{
			PointsSelectorOneOf: &qdrant.PointsSelector_Points{
				Points: &qdrant.PointsIdsList{
					Ids: []*qdrant.PointId{pointId},
				},
			},
		},
	}

	// 执行删除操作
	response, err := q.pointsClient.Delete(ctx, deleteRequest)
	if err != nil {
		log.Printf("Delete错误: %v", err)
		return fmt.Errorf("删除点失败: %v", err)
	}

	log.Printf("Delete响应: %+v", response)
	return nil
}

// convertToQdrantPayload 将Go的map转换为Qdrant的Payload格式
func convertToQdrantPayload(payload map[string]interface{}) (map[string]*qdrant.Value, error) {
	qdrantPayload := make(map[string]*qdrant.Value)

	for k, v := range payload {
		var value *qdrant.Value

		switch val := v.(type) {
		case string:
			value = &qdrant.Value{
				Kind: &qdrant.Value_StringValue{
					StringValue: val,
				},
			}
		case int:
			value = &qdrant.Value{
				Kind: &qdrant.Value_IntegerValue{
					IntegerValue: int64(val),
				},
			}
		case int64:
			value = &qdrant.Value{
				Kind: &qdrant.Value_IntegerValue{
					IntegerValue: val,
				},
			}
		case float64:
			value = &qdrant.Value{
				Kind: &qdrant.Value_DoubleValue{
					DoubleValue: val,
				},
			}
		case float32:
			value = &qdrant.Value{
				Kind: &qdrant.Value_DoubleValue{
					DoubleValue: float64(val),
				},
			}
		case bool:
			value = &qdrant.Value{
				Kind: &qdrant.Value_BoolValue{
					BoolValue: val,
				},
			}
		case time.Time:
			// 注释掉不支持的DatetimeValue类型
			// value = &qdrant.Value{
			// 	Kind: &qdrant.Value_DatetimeValue{
			// 		DatetimeValue: timestamppb.New(val),
			// 	},
			// }
			// 转换为字符串格式存储
			value = &qdrant.Value{
				Kind: &qdrant.Value_StringValue{
					StringValue: val.Format(time.RFC3339),
				},
			}
		case []string:
			strArray := &qdrant.ListValue{
				Values: make([]*qdrant.Value, len(val)),
			}
			for i, str := range val {
				strArray.Values[i] = &qdrant.Value{
					Kind: &qdrant.Value_StringValue{
						StringValue: str,
					},
				}
			}
			value = &qdrant.Value{
				Kind: &qdrant.Value_ListValue{
					ListValue: strArray,
				},
			}
		default:
			log.Printf("警告: 不支持的类型 %T 用于键 %s, 跳过", v, k)
			continue
		}

		qdrantPayload[k] = value
	}

	return qdrantPayload, nil
}
